<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Drawing with Cairo</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="GUI, PyGTK, Cairo, drawing, Python, programming, Linux">
<meta name="description" content="Drawing with Cairo">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Drawing with Cairo</h1>

<p>
In this part of the PyGTK programming tutorial, 
we will do some drawing with the Cairo library.
</p>


<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* NewSquare */
google_ad_slot = "0364418177";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script>


<p>
<b class="keyword">Cairo</b> is a library for creating 2D vector graphics. 
We can use it to draw our own widgets, charts or various effects or animations. 
</p>



<h2>Simple drawing</h2>

<p>
The stroke operation draws the outlines of shapes and the 
fill operation fills the insides of shapes. Next we will demonstrate
these two operations.
</p>

<div class="codehead">simpledrawing.py</div> 
<pre class="code">
#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This code example draws a circle
# using the cairo library
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009


import gtk
import math

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Simple drawing")
        self.resize(230, 150)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        darea = gtk.DrawingArea()
        darea.connect("expose-event", self.expose)
        self.add(darea)

        self.show_all()
    
    def expose(self, widget, event):

        cr = widget.window.cairo_create()

        cr.set_line_width(9)
        cr.set_source_rgb(0.7, 0.2, 0.0)
                
        w = self.allocation.width
        h = self.allocation.height

        cr.translate(w/2, h/2)
        cr.arc(0, 0, 50, 0, 2*math.pi)
        cr.stroke_preserve()
        
        cr.set_source_rgb(0.3, 0.4, 0.6)
        cr.fill()
    

PyApp()
gtk.main()
</pre>

<p>
In our example, we will draw a circle and will it with a solid color. 
</p>


<pre class="explanation">
 darea = gtk.DrawingArea()
</pre>

<p>
We will be doing our drawing operations on the <b class="keyword">DrawingArea</b> 
widget. 
</p>

<pre class="explanation">
 darea.connect("expose-event", self.expose)
</pre>

<p>
We do all drawing in a method, that is a handler for the
<b class="keyword">expose-event</b> signal. 
</p>

<pre class="explanation">
 cr = widget.window.cairo_create()
</pre>

<p>
We create the cairo context object from the
<b class="keyword">gdk.Window</b> of the drawing area. The context is an
object that is used to draw on all Drawable objects. 
</p>

<pre class="explanation">
 cr.set_line_width(9)
</pre>

<p>
We set the width of the line to 9 pixels.
</p>

<pre class="explanation">
 cr.set_source_rgb(0.7, 0.2, 0.0)
</pre>

<p>
We set the color to dark red. 
</p>

<pre class="explanation">
 w = self.allocation.width
 h = self.allocation.height

 cr.translate(w/2, h/2)
</pre>

<p>
We get the width and height of the drawing area. 
We move the origin into the middle of the window. 
</p>

<pre class="explanation">
 cr.arc(0, 0, 50, 0, 2*math.pi)
 cr.stroke_preserve()
</pre>

<p>
We draw the outside shape of a circle. In red color. The <b class="keyword">stroke_preserve()</b> 
strokes the current path according to the current line width, line join, line cap,
and dash settings. Unlike the <b class="keyword">stroke()</b>, 
it preserves the path within the cairo context. 
</p>

<pre class="explanation">
 cr.set_source_rgb(0.3, 0.4, 0.6)
 cr.fill()
</pre>

<p>
This fills the interior of the circle with some blue color.
</p>


<br>
<img src="/img/gui/pygtk/simpledrawing.png" alt="Simple drawing">
<div class="figure">Figure: Simple drawing</div>
<br>

<h2>Basic shapes</h2>

<p>
The next example draws some basic shapes onto the window. 
</p>

<div class="codehead">basicshapes.py</div> 
<pre class="code">
#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This code example draws basic shapes
# with the cairo library
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import math

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()
        
        self.set_title("Basic shapes")
        self.set_size_request(390, 240)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        darea = gtk.DrawingArea()
        darea.connect("expose-event", self.expose)
        self.add(darea)
        
        self.show_all()
    
    def expose(self, widget, event):

        cr = widget.window.cairo_create()
        cr.set_source_rgb(0.6, 0.6, 0.6)

        cr.rectangle(20, 20, 120, 80)
        cr.rectangle(180, 20, 80, 80)
        cr.fill()

        cr.arc(330, 60, 40, 0, 2*math.pi)
        cr.fill()
        
        cr.arc(90, 160, 40, math.pi/4, math.pi)
        cr.fill()

        cr.translate(220, 180)
        cr.scale(1, 0.7)
        cr.arc(0, 0, 50, 0, 2*math.pi)
        cr.fill()
    

PyApp()
gtk.main()
</pre>

<p>
In this example, we will create a rectangle, a square, a circle, an arc and an ellipse. 
</p>

<pre class="explanation">
 cr.rectangle(20, 20, 120, 80)
 cr.rectangle(180, 20, 80, 80)
 cr.fill()
</pre>

<p>
These lines draw a rectangle and a square. 
</p>

<pre class="explanation">
 cr.arc(330, 60, 40, 0, 2*math.pi)
 cr.fill()
</pre>

<p>
Here the <b class="keyword">arc()</b> method draws a full circle.
</p>

<pre class="explanation">
 cr.scale(1, 0.7)
 cr.arc(0, 0, 50, 0, 2*math.pi)
 cr.fill()
</pre>

<p>
If we want to draw an oval, we do some scaling first. Here the 
<b class="keyword">scale()</b> method shrinks the y axis.
</p>


<br>
<img src="/img/gui/pygtk/basicshapes.png" alt="Basic shapes">
<div class="figure">Figure: Basic shapes</div>
<br>


<h2>Colors</h2>

<p>
A color is an object representing a combination of Red, Green, 
and Blue (RGB) intensity values.
Cairo valid RGB values are in the range 0 to 1. 
</p>

<div class="codehead">colors.py</div> 
<pre class="code">
#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This program shows how to work
# with colors in cairo
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009


import gtk

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()
        
        self.set_title("Colors")
        self.resize(360, 100)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        darea = gtk.DrawingArea()
        darea.connect("expose-event", self.expose)
        self.add(darea)
        
        self.show_all()
    
    def expose(self, widget, event):

        cr = widget.window.cairo_create()

        cr.set_source_rgb(0.2, 0.23, 0.9)
        cr.rectangle(10, 15, 90, 60)
        cr.fill()
         
        cr.set_source_rgb(0.9, 0.1, 0.1)
        cr.rectangle(130, 15, 90, 60)
        cr.fill()

        cr.set_source_rgb(0.4, 0.9, 0.4)
        cr.rectangle(250, 15, 90, 60)
        cr.fill()

PyApp()
gtk.main()
</pre>

<p>
We draw three rectangles in three different colors.
</p>

<pre class="explanation">
 cr.set_source_rgb(0.2, 0.23, 0.9)
</pre>

<p>
The <b class="keyword">set_source_rgb()</b> method sets a color for the 
cairo context. The three parameters of the method are the color intensity
values. 
</p>

<pre class="explanation">
 cr.rectangle(10, 15, 90, 60)
 cr.fill()
</pre>

<p>
We create a rectangle shape and fill it with the previously specified 
color. 
</p>

<br>
<img src="/img/gui/pygtk/colors.png" alt="Colors">
<div class="figure">Figure: Colors</div>
<br>


<h2>Transparent rectangles</h2>

<p>
Transparency is the quality of being able to see through a material. 
The easiest way to understand transparency is to imagine a piece of 
glass or water. Technically, the rays of light can go through the glass 
and this way we can see objects behind the glass.
</p>

<p>
In computer graphics, we can achieve transparency effects using alpha 
compositing. Alpha compositing is the process of combining an image with 
a background to create the appearance of partial transparency. 
The composition process uses an alpha channel. (wikipedia.org, answers.com)
</p>

<div class="codehead">transparentrectangles.py</div>
<pre class="code">
#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This program shows transparent
# rectangles using cairo
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009


import gtk

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()
        
        self.set_title("Transparent rectangles")
        self.resize(590, 90)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        darea = gtk.DrawingArea()
        darea.connect("expose-event", self.expose)
        self.add(darea)
        
        self.show_all()
    
    def expose(self, widget, event):

        cr = widget.window.cairo_create()

        for i in range(1, 11):
            cr.set_source_rgba(0, 0, 1, i*0.1)
            cr.rectangle(50*i, 20, 40, 40)
            cr.fill()


PyApp()
gtk.main()
</pre>

<p>
In the example we will draw ten rectangles with different levels of transparency. 
</p>

<pre class="explanation">
 cr.set_source_rgba(0, 0, 1, i*0.1)
</pre>

<p>
The last parameter of the <b class="keyword">set_source_rgba()</b> method is the
alpha transparency.
</p>


<br>
<img src="/img/gui/pygtk/transparency.png" alt="Transparent rectangles">
<div class="figure">Figure: Transparent rectangles</div>
<br>

<h2>Soulmate</h2>

<p>
In the next example, we draw some text on the window. 
</p>

<div class="codehead">soulmate.py</div>
<pre class="code">
#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This program draws text
# using cairo
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009


import gtk
import cairo

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()
        
        self.set_title("Soulmate")
        self.set_size_request(370, 240)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        darea = gtk.DrawingArea()
        darea.connect("expose-event", self.expose)
        self.add(darea)
        
        self.show_all()
    
    def expose(self, widget, event):

        cr = widget.window.cairo_create()

        cr.set_source_rgb(0.1, 0.1, 0.1)
         
        cr.select_font_face("Purisa", cairo.FONT_SLANT_NORMAL, 
            cairo.FONT_WEIGHT_NORMAL)
        cr.set_font_size(13)
       
        cr.move_to(20, 30)
        cr.show_text("Most relationships seem so transitory")
        cr.move_to(20, 60)
        cr.show_text("They're all good but not the permanent one")
        cr.move_to(20, 120)
        cr.show_text("Who doesn't long for someone to hold")
        cr.move_to(20, 150)
        cr.show_text("Who knows how to love without being told")
        cr.move_to(20, 180)
        cr.show_text("Somebody tell me why I'm on my own")
        cr.move_to(20, 210)
        cr.show_text("If there's a soulmate for everyone")
        

PyApp()
gtk.main()
</pre>

<p>
We display part of the lyrics from the Natasha Bedingfields Soulmate song. 
</p>

<pre class="explanation">
  cr.select_font_face("Purisa", cairo.FONT_SLANT_NORMAL, 
      cairo.FONT_WEIGHT_NORMAL)
</pre>

<p>
Here we specify the font, that we use.
</p>

<pre class="explanation">
 cr.set_font_size(13)
</pre>

<p>
We specify the size of the font.
</p>

<pre class="explanation">
 cr.move_to(20, 30)
</pre>

<p>
We move to the point, where we will draw the text. 
</p>

<pre class="explanation">
 cr.show_text("Most relationships seem so transitory")
</pre>

<p>
The <b class="keyword">show_text()</b> method draws text onto the window. 
</p>


<br>
<img src="/img/gui/pygtk/soulmate.png" alt="Soulmate">
<div class="figure">Figure: Soulmate</div>


<hr class="btm">


<p>
In this chapter of the PyGTK programming library, we were drawing 
with the Cairo graphics library.
</p>


<br>
<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div> 
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified February 8, 2009  <span class="copyright">&copy; 2007 - 2012 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>

